use async_trait::async_trait;
use glass::{name, reflect, AsyncCallable, Callable, TraitAsyncCallable};
use glass::{Reflect, Value};
use glass_expand::reflect_attribute::ReflectAttr;
use syn::{parse_quote, Item};

#[derive(Reflect)]
struct Student {
    pub name: String,
}

#[reflect]
impl Student {
    /// 创建实例
    #[name("new")]
    fn new(name: String) -> Self {
        println!("new {name}~");
        Self { name }
    }

    /// print test
    ///
    /// hello
    /// # title 1
    pub async fn b(age: i32) {
        println!("print b {age} ~");
    }
}

/// print fn student
#[reflect(class = Student)]
pub async fn abc(age: i32) -> i32 {
    println!("{age}");
    32
}

#[reflect(class = Student)]
#[async_trait]
pub trait Tt<T>: Sized {
    /// print class student
    async fn print(age: i32, name: String) -> String;
}

#[reflect]
#[async_trait]
impl Tt<i32> for Student {
    #[name("打印")]
    async fn print(age: i32, name: String) -> String {
        println!("tt --- {age}");
        name
    }
}

#[tokio::test]
async fn b() {
    let type_info = Student::type_info();
    for func in type_info.funcs.iter() {
        println!("docs = {:?}", func.docs);
        println!("attrs = {:?}", func.attrs);
        if let Some(function) = &func.function {
            match &function {
                glass::FunctionWrapper::Sync(sync_function) => {
                    sync_function
                        .call(vec![Value::Any(Box::new(String::from("lisi")))])
                        .unwrap();
                }
                glass::FunctionWrapper::Async(async_function) => {
                    async_function
                        .async_call(vec![Value::I32(30)])
                        .await
                        .unwrap();
                }
                glass::FunctionWrapper::TraitAsync(trait_async_function) => {
                    trait_async_function
                        .async_call(vec![Value::I32(31), Value::String(String::from("aa"))])
                        .await
                        .unwrap();
                }
            }
        }
    }
}

#[test]
fn test_expand() {
    let mut input: Item = parse_quote! {
        #[async_trait]
        pub trait Tt<T>: Sized {
            /// print class student
            #[name("abc")]
            async fn print(age: i32, name: String) -> String;
        }
    };

    let result = glass_expand::reflect_attribute::expand(
        &mut ReflectAttr {
            callable: None,
            class: None,
        },
        &mut input,
    );
    println!("{}", result.unwrap());
}
